home *** CD-ROM | disk | FTP | other *** search
/ Sprite 1984 - 1993 / Sprite 1984 - 1993.iso / src / kernel / fscache / fscacheOps.c < prev    next >
C/C++ Source or Header  |  1992-12-18  |  38KB  |  1,242 lines

  1. /* 
  2.  * fsCacheOps.c --
  3.  *
  4.  *    Cache routines that are monitored with the lock in the per-file
  5.  *    cacheInfo structure.  This includes high level read and write
  6.  *    routines, and routines that fiddle with the attributes that
  7.  *    are cached.
  8.  *    
  9.  *
  10.  * Copyright 1987 Regents of the University of California
  11.  * All rights reserved.
  12.  * Permission to use, copy, modify, and distribute this
  13.  * software and its documentation for any purpose and without
  14.  * fee is hereby granted, provided that the above copyright
  15.  * notice appear in all copies.  The University of California
  16.  * makes no representations about the suitability of this
  17.  * software for any purpose.  It is provided "as is" without
  18.  * express or implied warranty.
  19.  */
  20.  
  21. #ifndef lint
  22. static char rcsid[] = "$Header: /cdrom/src/kernel/Cvsroot/kernel/fscache/fscacheOps.c,v 9.21 92/10/26 13:55:23 mgbaker Exp $ SPRITE (Berkeley)";
  23. #endif not lint
  24.  
  25.  
  26. #include <sprite.h>
  27. #include <fs.h>
  28. #include <fsutil.h>
  29. #include <fscache.h>
  30. #include <fsconsist.h>
  31. #include <fsNameOps.h>
  32. #include <fsdm.h>
  33. #include <fsStat.h>
  34. #include <fslcl.h>
  35. #include <fscacheBlocks.h>
  36. #include <vm.h>
  37. #include <spriteTime.h>
  38. #include <timer.h>
  39. #include <sys.h>
  40. #include <rpc.h>
  41.  
  42. #define    BLOCK_ALIGNED(offset) (((offset) & ~FS_BLOCK_OFFSET_MASK) == (offset))
  43.  
  44. /*
  45.  * Cache I/O is serialized using a monitor lock on the cache state for
  46.  * each file.
  47.  */
  48. #define LOCKPTR (&cacheInfoPtr->lock)
  49.  
  50.  
  51. /*
  52.  * ----------------------------------------------------------------------------
  53.  *
  54.  * Fscache_UpdateFile --
  55.  *
  56.  *     This routine updates the cacheInfo for a file based on info returned
  57.  *    from the server at open time.  It checks version numbers and the
  58.  *    cachability of the file, and will do any required invalidations.
  59.  *
  60.  * Results:
  61.  *    True if the file in the cache is different than before.  This is
  62.  *    used to tell VM that the cached segment representing the file
  63.  *    is no longer valid.
  64.  *
  65.  * Side effects:
  66.  *    Updates the version number.  May invalidate old blocks.
  67.  *
  68.  * ----------------------------------------------------------------------------
  69.  *
  70.  */
  71. ENTRY Boolean
  72. Fscache_UpdateFile(cacheInfoPtr, openForWriting, version, cacheable, attrPtr)
  73.     Fscache_FileInfo *cacheInfoPtr;    /* Cache state of file to update. */
  74.     Boolean        openForWriting;    /* TRUE if opening for writing */
  75.     int            version;    /* Version number used to verify
  76.                      * our cached data blocks. */
  77.     Boolean        cacheable;    /* TRUE if server says we can cache. */
  78.     Fscache_Attributes    *attrPtr;    /* Attributes from server */
  79. {
  80.     register Boolean outOfDate;
  81.     Boolean changed = FALSE;
  82.     LOCK_MONITOR;
  83.  
  84.     /* 
  85.      * See if we have a good cached copy.  Note: if we open for writing
  86.      * the returned version number will be one greater than ours
  87.      * if no-one else has modified the file since we cached it.
  88.      */
  89.  
  90.     if (openForWriting) {
  91.     outOfDate = (cacheInfoPtr->version < version - 1);
  92.     } else {
  93.     outOfDate = (cacheInfoPtr->version < version);
  94.     }
  95.     if (version > cacheInfoPtr->version) {
  96.     /*
  97.      * Update the version of the handle, ie. we just opened for writing
  98.      * or had an outOfDate version.
  99.      */
  100.     cacheInfoPtr->version = version;
  101.     changed = TRUE;
  102.     }
  103.     if (cacheInfoPtr->flags & FSCACHE_FILE_GONE) {
  104.     /*
  105.      * Reset the deleted bit.  By this time any deletion
  106.      * actions will have completed.
  107.      */
  108.     cacheInfoPtr->flags &= ~FSCACHE_FILE_GONE;
  109.     }
  110.  
  111.     /*
  112.      * If we were caching and the file is no longer cacheable, or our copy
  113.      * is outOfDate, we need to invalidate our cache.  Note that we do
  114.      * the cache invalidate with our previous notion of the size.
  115.      */
  116.     if (!cacheable || outOfDate) {
  117.     fs_Stats.handle.cacheFlushes++;
  118.     Fscache_FileInvalidate(cacheInfoPtr, 0, FSCACHE_LAST_BLOCK);
  119.     }
  120.     if (outOfDate) {
  121.     fs_Stats.handle.versionMismatch++;
  122.     cacheInfoPtr->attr = *attrPtr;
  123.     }
  124.  
  125.     /*
  126.      * Propogate the cachability of the handle.
  127.      */
  128.     if (cacheable) {
  129.     if (cacheInfoPtr->flags & FSCACHE_FILE_NOT_CACHEABLE) {
  130.         /*
  131.          * The handle wasn't client cacheable before.  In this
  132.          * case mark the handle as cacheable and update the cached
  133.          * attributes since they could have changed 
  134.          * while we didn't have the file cached.
  135.          */
  136.         cacheInfoPtr->attr = *attrPtr;
  137.         cacheInfoPtr->flags &= ~FSCACHE_FILE_NOT_CACHEABLE;
  138.     }
  139.     } else {
  140.     cacheInfoPtr->flags |= FSCACHE_FILE_NOT_CACHEABLE;
  141.     }
  142.  
  143.     /* 
  144.      * Update the handle's access time.  The access time doesn't get
  145.      * pushed out to all clients concurrently read-sharing a file,
  146.      * so we grab it here if we are out-of-date.
  147.      */
  148.     if (attrPtr->accessTime > cacheInfoPtr->attr.accessTime) {
  149.     cacheInfoPtr->attr.accessTime = attrPtr->accessTime;
  150.     }
  151.     UNLOCK_MONITOR;
  152.     return (changed);
  153. }
  154.  
  155. /*
  156.  * ----------------------------------------------------------------------------
  157.  *
  158.  * Fscache_UpdateAttrFromClient --
  159.  *
  160.  *     This is used on the server to update the attributes of a handle
  161.  *    that has been cached on a client.  Called at close time with
  162.  *    the attributes the client sends over with the close RPC.
  163.  *    The client's times are checked against the servers to ensure
  164.  *    that they only increase and never move backwards.
  165.  *
  166.  * Results:
  167.  *    None.
  168.  *
  169.  * Side effects:
  170.  *    Updates the access and modify time if they are greater than
  171.  *    the local attribute.  Updates the first and last byte indexes.
  172.  *
  173.  * ----------------------------------------------------------------------------
  174.  *
  175.  */
  176. ENTRY void
  177. Fscache_UpdateAttrFromClient(clientID, cacheInfoPtr, attrPtr)
  178.     int clientID;                /* Client, for warning msg */
  179.     register Fscache_FileInfo *cacheInfoPtr;    /* Cache state to update. */
  180.     register Fscache_Attributes    *attrPtr;    /* Attributes from client */
  181. {
  182.     LOCK_MONITOR;
  183.  
  184.     if (attrPtr->modifyTime > cacheInfoPtr->attr.modifyTime) {
  185.     cacheInfoPtr->attr.modifyTime = attrPtr->modifyTime;
  186.     }
  187.     if (attrPtr->accessTime > cacheInfoPtr->attr.accessTime) {
  188.     cacheInfoPtr->attr.accessTime = attrPtr->accessTime;
  189.     }
  190.     if (cacheInfoPtr->attr.lastByte > attrPtr->lastByte) {
  191.     printf(
  192.     "Fscache_UpdateAttrFromClient %d: \"%s\" <%d,%d> short size %d not %d\n",
  193.         clientID,
  194.         Fsutil_HandleName(cacheInfoPtr->hdrPtr),
  195.         cacheInfoPtr->hdrPtr->fileID.major,
  196.         cacheInfoPtr->hdrPtr->fileID.minor,
  197.         attrPtr->lastByte, cacheInfoPtr->attr.lastByte);
  198.     } else {
  199.     cacheInfoPtr->attr.lastByte = attrPtr->lastByte;
  200.     }
  201.     cacheInfoPtr->attr.firstByte = attrPtr->firstByte;
  202.  
  203.     (void)Fsdm_UpdateDescAttr((Fsio_FileIOHandle *)cacheInfoPtr->hdrPtr, 
  204.         &cacheInfoPtr->attr, -1);
  205.     UNLOCK_MONITOR;
  206. }
  207.  
  208. /*
  209.  * ----------------------------------------------------------------------------
  210.  *
  211.  * Fscache_UpdateDirSize --
  212.  *
  213.  *     This is used on the server to update the size of a directory
  214.  *    when it grows due to additions.  Note that directories don't
  215.  *    get smaller.
  216.  *
  217.  * Results:
  218.  *    None.
  219.  *
  220.  * Side effects:
  221.  *    Updates the last byte index.
  222.  *
  223.  * ----------------------------------------------------------------------------
  224.  *
  225.  */
  226. ENTRY void
  227. Fscache_UpdateDirSize(cacheInfoPtr, newLastByte)
  228.     register Fscache_FileInfo *cacheInfoPtr;    /* Cache state to update. */
  229.     register int newLastByte;            /* New last byte index */
  230. {
  231.     LOCK_MONITOR;
  232.     if (newLastByte > cacheInfoPtr->attr.lastByte) {
  233.     cacheInfoPtr->attr.lastByte = newLastByte;
  234.     }
  235.     UNLOCK_MONITOR;
  236. }
  237.  
  238. /*
  239.  * ----------------------------------------------------------------------------
  240.  *
  241.  * Fscache_UpdateAttrFromCache --
  242.  *
  243.  *     This is used on a client to update the given attributes from
  244.  *    information it has cached.  A client caches the access time,
  245.  *    modify time, and size of a file.  When the server returns attributes,
  246.  *    this routine is called to complete them from info cached here
  247.  *    on the client.
  248.  *
  249.  * Results:
  250.  *    None.
  251.  *
  252.  * Side effects:
  253.  *    Updates the access and modify time of *attrPtr if they are less than
  254.  *    the cached value.  Always updates the first and last byte indexes
  255.  *    with the cached value.
  256.  *
  257.  * ----------------------------------------------------------------------------
  258.  *
  259.  */
  260. ENTRY void
  261. Fscache_UpdateAttrFromCache(cacheInfoPtr, attrPtr)
  262.     register Fscache_FileInfo *cacheInfoPtr;    /* Cache state to check. */
  263.     register Fs_Attributes    *attrPtr;    /* Attributes from server */
  264. {
  265.     LOCK_MONITOR;
  266.     if ((cacheInfoPtr->version == attrPtr->version) &&
  267.     (cacheInfoPtr->flags & FSCACHE_FILE_NOT_CACHEABLE) == 0) {
  268.     if (cacheInfoPtr->attr.accessTime > attrPtr->accessTime.seconds) {
  269.         attrPtr->accessTime.seconds = cacheInfoPtr->attr.accessTime;
  270.     }
  271.     if (cacheInfoPtr->attr.modifyTime > attrPtr->dataModifyTime.seconds) {
  272.         attrPtr->dataModifyTime.seconds = cacheInfoPtr->attr.modifyTime;
  273.     }
  274.     attrPtr->size = cacheInfoPtr->attr.lastByte + 1;
  275.     if (cacheInfoPtr->attr.firstByte > 0) {
  276.         attrPtr->size -= cacheInfoPtr->attr.firstByte;
  277.     }
  278.     }
  279.     UNLOCK_MONITOR;
  280. }
  281.  
  282. /*
  283.  * ----------------------------------------------------------------------------
  284.  *
  285.  * Fscache_GetCachedAttr --
  286.  *
  287.  *     This is used on a server to fill out the attributes returned to
  288.  *    a client for caching there.
  289.  *
  290.  * Results:
  291.  *    None.
  292.  *
  293.  * Side effects:
  294.  *    None.
  295.  *
  296.  * ----------------------------------------------------------------------------
  297.  *
  298.  */
  299. ENTRY void
  300. Fscache_GetCachedAttr(cacheInfoPtr, versionPtr, attrPtr)
  301.     register Fscache_FileInfo    *cacheInfoPtr;    /* Cache state to update. */
  302.     register int        *versionPtr;    /* Version number of file */
  303.     register Fscache_Attributes    *attrPtr;    /* New attributes from server */
  304. {
  305.     LOCK_MONITOR;
  306.     *versionPtr = cacheInfoPtr->version;
  307.     *attrPtr = cacheInfoPtr->attr;
  308.     UNLOCK_MONITOR;
  309. }
  310.  
  311. /*
  312.  * ----------------------------------------------------------------------------
  313.  *
  314.  * Fscache_UpdateCachedAttr --
  315.  *
  316.  *     This is called during an Fs_SetAttributes call to update attributes
  317.  *    that are cached in a handle.
  318.  *
  319.  * Results:
  320.  *    None.
  321.  *
  322.  * Side effects:
  323.  *    Updates the times, permissions, file type, and ownership info,
  324.  *    depending on the flags argument.
  325.  *
  326.  * ----------------------------------------------------------------------------
  327.  *
  328.  */
  329. ENTRY void
  330. Fscache_UpdateCachedAttr(cacheInfoPtr, attrPtr, flags)
  331.     register Fscache_FileInfo *cacheInfoPtr;    /* Cache state to update. */
  332.     register Fs_Attributes   *attrPtr;        /* New attributes */
  333.     register int         flags;        /* What attrs to update */
  334. {
  335.     LOCK_MONITOR;
  336.     if (flags & FS_SET_TIMES) {
  337.     cacheInfoPtr->attr.accessTime = attrPtr->accessTime.seconds;
  338.     cacheInfoPtr->attr.modifyTime = attrPtr->dataModifyTime.seconds;
  339.     cacheInfoPtr->attr.createTime = attrPtr->createTime.seconds;
  340.     }
  341.     if (flags & FS_SET_MODE) {
  342.     cacheInfoPtr->attr.permissions = attrPtr->permissions;
  343.     }
  344.     if (flags & FS_SET_OWNER) {
  345.     if (attrPtr->uid >= 0) {
  346.         cacheInfoPtr->attr.uid = attrPtr->uid;
  347.     }
  348.     if (attrPtr->gid >= 0) {
  349.         cacheInfoPtr->attr.gid = attrPtr->gid;
  350.     }
  351.     }
  352.     if ((flags & FS_SET_FILE_TYPE) &&
  353.     attrPtr->userType != FS_USER_TYPE_UNDEFINED) {
  354.     cacheInfoPtr->attr.userType = attrPtr->userType;
  355.     }
  356.     UNLOCK_MONITOR;
  357. }
  358.  
  359. /*
  360.  * ----------------------------------------------------------------------------
  361.  *
  362.  * Fscache_CheckVersion --
  363.  *
  364.  *     This is used during recovery on a server to see if the client
  365.  *    has an ok version of the file.
  366.  *
  367.  * Results:
  368.  *    FS_VERSION_MISMATCH if the client's version number is out-of-date.
  369.  *
  370.  * Side effects:
  371.  *    None, except for a print statement.
  372.  *
  373.  * ----------------------------------------------------------------------------
  374.  *
  375.  */
  376. ENTRY ReturnStatus
  377. Fscache_CheckVersion(cacheInfoPtr, version, clientID)
  378.     register Fscache_FileInfo    *cacheInfoPtr;    /* Cache state to check. */
  379.     int                version;
  380.     int                clientID;
  381. {
  382.     ReturnStatus status = SUCCESS;
  383.     LOCK_MONITOR;
  384.     if (version != cacheInfoPtr->version) {
  385.     printf(
  386.     "Version mismatch: clt %d, srv %d, file \"%s\" <%d,%d>, from client %d\n",
  387.         version, cacheInfoPtr->version, Fsutil_HandleName(cacheInfoPtr->hdrPtr),
  388.         cacheInfoPtr->hdrPtr->fileID.major,
  389.         cacheInfoPtr->hdrPtr->fileID.minor, clientID);
  390.     status = FS_VERSION_MISMATCH;
  391.     }
  392.     UNLOCK_MONITOR;
  393.     return(status);
  394. }
  395.  
  396. /*
  397.  * ----------------------------------------------------------------------------
  398.  *
  399.  * Fscache_OkToScavenge --
  400.  *
  401.  *     This is called at handle scavenge time to see if it is ok to
  402.  *    scavenge the handle.  This calls a routine in fsBlockCache.c
  403.  *    which gets the global cache monitor lock because the blocksInCache
  404.  *    attribute and FS_FILE_ON_DIRTY list flags is modified under that lock.
  405.  *
  406.  * Results:
  407.  *    TRUE if there is no information in the cache for the file.
  408.  *
  409.  * Side effects:
  410.  *    None.
  411.  *
  412.  * ----------------------------------------------------------------------------
  413.  *
  414.  */
  415. ENTRY Boolean
  416. Fscache_OkToScavenge(cacheInfoPtr)
  417.     register Fscache_FileInfo    *cacheInfoPtr;    /* Cache state to check. */
  418. {
  419.     register Boolean ok;
  420.     LOCK_MONITOR;
  421.     ok = FscacheBlockOkToScavenge(cacheInfoPtr);
  422.     UNLOCK_MONITOR;
  423.     return(ok);
  424. }
  425.  
  426. /*
  427.  * ----------------------------------------------------------------------------
  428.  *
  429.  * Fscache_OkToScavengeExceptDirty --
  430.  *
  431.  *     This is called at handle reopen time to see if it is necessary to
  432.  *    reopen the handle.  This calls a routine in fsBlockCache.c
  433.  *    which gets the global cache monitor lock because the blocksInCache
  434.  *    attribute and FS_FILE_ON_DIRTY list flags is modified under that lock.
  435.  *
  436.  * Results:
  437.  *    TRUE if there are no references to or dirty blocks for the file.
  438.  *
  439.  * Side effects:
  440.  *    None.
  441.  *
  442.  * ----------------------------------------------------------------------------
  443.  *
  444.  */
  445. ENTRY Boolean
  446. Fscache_OkToScavengeExceptDirty(cacheInfoPtr)
  447.     register Fscache_FileInfo    *cacheInfoPtr;    /* Cache state to check. */
  448. {
  449.     register Boolean ok;
  450.     LOCK_MONITOR;
  451.     ok = FscacheBlockOkToScavengeExceptDirty(cacheInfoPtr);
  452.     UNLOCK_MONITOR;
  453.     return(ok);
  454. }
  455.  
  456. /*
  457.  * ----------------------------------------------------------------------------
  458.  *
  459.  * Fscache_Consist --
  460.  *
  461.  *     This is called from ProcessConsist to take a cache consistency
  462.  *    action in response to a callback from the file server.
  463.  *
  464.  * Results:
  465.  *    The return status from the block cache operations, plus the
  466.  *    values of the attributes we have cached here on the client.
  467.  *
  468.  * Side effects:
  469.  *    Will writeback and/or invalidate the cache according to the
  470.  *    request by the server.
  471.  *
  472.  * ----------------------------------------------------------------------------
  473.  *
  474.  */
  475. ENTRY ReturnStatus
  476. Fscache_Consist(cacheInfoPtr, flags, cachedAttrPtr)
  477.     register Fscache_FileInfo    *cacheInfoPtr;
  478.     int                flags;
  479.     Fscache_Attributes        *cachedAttrPtr;
  480. {
  481.     ReturnStatus status;
  482.     int firstBlock;
  483.     int numSkipped;
  484.     int mig;
  485.  
  486.     LOCK_MONITOR;
  487.  
  488.     if (cacheInfoPtr->attr.firstByte == -1) {
  489.     firstBlock = 0;
  490.     } else {
  491.     firstBlock = cacheInfoPtr->attr.firstByte / FS_BLOCK_SIZE;
  492.     }
  493.     status = SUCCESS;
  494.     mig = (flags & FSCONSIST_MIGRATION) ? FSCACHE_WB_MIGRATION : 0;
  495.     switch (flags & ~(FSCONSIST_MIGRATION)) {
  496.     case FSCONSIST_WRITE_BACK_BLOCKS:
  497.         status = Fscache_FileWriteBack(cacheInfoPtr, firstBlock,
  498.             FSCACHE_LAST_BLOCK, FSCACHE_FILE_WB_WAIT | mig,
  499.                        &numSkipped);
  500.         break;
  501.     case FSCONSIST_CANT_CACHE_NAMED_PIPE:
  502.     case FSCONSIST_INVALIDATE_BLOCKS:
  503.         Fscache_FileInvalidate(cacheInfoPtr, firstBlock, 
  504.                    FSCACHE_LAST_BLOCK);
  505.         cacheInfoPtr->flags |= FSCACHE_FILE_NOT_CACHEABLE;
  506.         break;
  507.     case FSCONSIST_INVALIDATE_BLOCKS | FSCONSIST_WRITE_BACK_BLOCKS:
  508.         status = Fscache_FileWriteBack(cacheInfoPtr, firstBlock,
  509.                        FSCACHE_LAST_BLOCK,
  510.                        FSCACHE_WRITE_BACK_AND_INVALIDATE |
  511.                        FSCACHE_FILE_WB_WAIT | mig,
  512.                        &numSkipped);
  513.         cacheInfoPtr->flags |= FSCACHE_FILE_NOT_CACHEABLE;
  514.         break;
  515.     case FSCONSIST_DELETE_FILE:
  516.         cacheInfoPtr->flags |= FSCACHE_FILE_GONE;
  517.         Fscache_FileInvalidate(cacheInfoPtr, firstBlock, FSCACHE_LAST_BLOCK);
  518.         cacheInfoPtr->flags |= FSCACHE_FILE_NOT_CACHEABLE;
  519.         break;
  520.     case FSCONSIST_WRITE_BACK_ATTRS:
  521.         break;
  522.     default:
  523.         printf("Fscache_Consist: Bad consistency action %x\n", flags);
  524.         status = FS_INVALID_ARG;
  525.         break;
  526.     }
  527.     *cachedAttrPtr = cacheInfoPtr->attr;
  528.  
  529.     UNLOCK_MONITOR;
  530.     return(status);
  531. }
  532.  
  533. /*
  534.  *----------------------------------------------------------------------
  535.  *
  536.  * Fscache_Read --
  537.  *
  538.  *    Read from the block cache.
  539.  *
  540.  * Results:
  541.  *    SUCCESS unless there was an address error or I/O error.
  542.  *
  543.  * Side effects:
  544.  *    Fill in the buffer and the cache with data from the stream.
  545.  *    The cache state for the file is locked to serialize I/O.
  546.  *
  547.  *----------------------------------------------------------------------
  548.  */
  549. ReturnStatus
  550. Fscache_Read(cacheInfoPtr, flags, buffer, offset, lenPtr, remoteWaitPtr)
  551.     register Fscache_FileInfo *cacheInfoPtr;    /* Cache state for file. */
  552.     int            flags;        /* FS_USER | etc */
  553.     register Address    buffer;        /* Buffer to fill with file data */
  554.     int         offset;        /* Byte offset */
  555.     int         *lenPtr;    /* In/Out byte count */
  556.     Sync_RemoteWaiter    *remoteWaitPtr;    /* Process info for remote waiting */
  557. {
  558.     register int     size;        /* Amount left to read */
  559.     register int     blockNum;    /* Current block being read */
  560.     register int     toRead;        /* Amount to read each iteration */
  561.     ReturnStatus    status = SUCCESS; /* Return from I/O operations */
  562.     int            firstBlock;    /* First block of the read */
  563.     int            lastBlock;    /* Last block of the read */
  564.     Boolean        found;        /* For fetching blocks from cache */
  565.     Fscache_Block    *blockPtr;    /* For fetching blocks from cache */
  566.     int            dontBlock;    /* FSCACHE_DONT_BLOCK */
  567.  
  568.     /*
  569.      * Serialiaze access to the cache for this file.
  570.      */
  571.     LOCK_MONITOR;
  572.  
  573.     if (cacheInfoPtr->flags & FSCACHE_FILE_NOT_CACHEABLE) {
  574.     status = FS_NOT_CACHEABLE;
  575.     goto exit;
  576.     }
  577.     /*
  578.      * Determine the offset at which to read.
  579.      */
  580.     if (offset > cacheInfoPtr->attr.lastByte) {
  581.     *lenPtr = 0;
  582.     status = SUCCESS;
  583.     goto exit;
  584.     }
  585.  
  586.     if ((remoteWaitPtr != (Sync_RemoteWaiter *)NIL) &&
  587.     (remoteWaitPtr->pid != (Proc_PID)NIL)) {
  588.     dontBlock = FSCACHE_DONT_BLOCK;
  589.     } else {
  590.     dontBlock = 0;
  591.     }
  592.     /*
  593.      * Fetch blocks one at a time.
  594.      */
  595.     size = *lenPtr;
  596.     firstBlock = (unsigned int) offset / FS_BLOCK_SIZE; 
  597.     lastBlock = (unsigned int) (offset + size - 1) / FS_BLOCK_SIZE;
  598.  
  599.     for (blockNum = firstBlock; 
  600.      blockNum <= lastBlock && offset <= cacheInfoPtr->attr.lastByte; 
  601.      blockNum++, size -= toRead, buffer += toRead, offset += toRead) {
  602.  
  603.     /*
  604.      * Initiate read ahead on the next block.
  605.      */
  606.     FscacheReadAhead(cacheInfoPtr, blockNum + 1);
  607.  
  608.     /*
  609.      * Determine the number of bytes to transfer out of the cache block
  610.      * in this go around.
  611.      */
  612.     toRead = size;
  613.     if ((unsigned int) (offset + size - 1) / FS_BLOCK_SIZE > blockNum) {
  614.         toRead = (blockNum + 1) * FS_BLOCK_SIZE - offset;
  615.     }
  616.     if (toRead > cacheInfoPtr->attr.lastByte - offset + 1) {
  617.         toRead = cacheInfoPtr->attr.lastByte - offset + 1;
  618.     }
  619.  
  620.     /* 
  621.      * Get the block from the cache.  If the block isn't in the cache
  622.      * then read data into it.
  623.      */
  624.     Fscache_FetchBlock(cacheInfoPtr, blockNum,
  625.         FSCACHE_DATA_BLOCK|dontBlock, &blockPtr, &found);
  626.     if (blockPtr == (Fscache_Block *)NIL) {
  627.         /*
  628.          * Cache is full.
  629.          */
  630.         status = FS_WOULD_BLOCK;
  631.         Fsutil_WaitListInsert(fscacheFullWaitList, remoteWaitPtr);
  632.         break;
  633.     }
  634.     fs_Stats.blockCache.readAccesses++;
  635.     if (found) {
  636.         if (blockPtr->timeDirtied != 0) {
  637.         fs_Stats.blockCache.readHitsOnDirtyBlock++;
  638.         } else {
  639.         fs_Stats.blockCache.readHitsOnCleanBlock++;
  640.         }
  641.         if (blockPtr->flags & FSCACHE_READ_AHEAD_BLOCK) {
  642.         fs_Stats.blockCache.readAheadHits++;
  643.         }
  644.     } else {
  645.         /*
  646.          * We didn't find the block in the cache so we have to read it in.
  647.          * Fscache_FetchBlock has set the blockNum and blockAddr (buffer).
  648.          * blockSize gets set as a side-effect of the block read routine.
  649.          */
  650.         status = (cacheInfoPtr->backendPtr->ioProcs.blockRead)
  651.             (cacheInfoPtr->hdrPtr, blockPtr, remoteWaitPtr);
  652. #ifdef lint
  653.         status = Fsio_FileBlockRead(cacheInfoPtr->hdrPtr,
  654.             blockPtr, remoteWaitPtr);
  655.         status = FsrmtFileBlockRead(cacheInfoPtr->hdrPtr,
  656.             blockPtr, remoteWaitPtr);
  657. #endif /* lint */
  658.         if (status != SUCCESS) {
  659.         fs_Stats.blockCache.domainReadFails++;
  660.         Fscache_UnlockBlock(blockPtr, (time_t)0, -1, 0,
  661.                     FSCACHE_DELETE_BLOCK);
  662.         break;
  663.         }
  664.         }
  665.  
  666.     /*
  667.      * Copy the bytes out of the cache block.
  668.      */
  669.     if (flags & FS_USER) {
  670.         if (Vm_CopyOut(toRead, 
  671.                   blockPtr->blockAddr + (offset & FS_BLOCK_OFFSET_MASK),
  672.               buffer) != SUCCESS) {
  673.         status = SYS_ARG_NOACCESS;
  674.         Fscache_UnlockBlock(blockPtr, (time_t)0, -1, 0,
  675.             FSCACHE_CLEAR_READ_AHEAD);
  676.         break;
  677.         }
  678.     } else {
  679.         bcopy(blockPtr->blockAddr + (offset & FS_BLOCK_OFFSET_MASK),
  680.               buffer, toRead);
  681.     }
  682.     Fscache_UnlockBlock(blockPtr, (time_t)0, -1, 0,
  683.                 FSCACHE_CLEAR_READ_AHEAD);
  684.     }
  685.     *lenPtr -= size;
  686.     Fs_StatAdd(*lenPtr, fs_Stats.blockCache.bytesRead,
  687.            fs_Stats.blockCache.bytesReadOverflow);
  688. exit:
  689.     if ((status == SUCCESS) ||
  690.     (status == FS_WOULD_BLOCK && (*lenPtr > 0))) {
  691.     cacheInfoPtr->attr.accessTime = Fsutil_TimeInSeconds();
  692.     }
  693.     UNLOCK_MONITOR;
  694.     return(status);
  695. }
  696.  
  697. /*
  698.  *----------------------------------------------------------------------
  699.  *
  700.  * Fscache_Write --
  701.  *
  702.  *    Write to the cache.  Called from the file write and named pipe
  703.  *    write routines.
  704.  * 
  705.  * Results:
  706.  *    A return status, SUCCESS if successful.
  707.  *
  708.  * Side effects:
  709.  *    Data is put into the cache.  Blocks may be read if only partial
  710.  *    blocks are being written.  The cache state is locked during the I/O
  711.  *    to serialize cache access.
  712.  *
  713.  *----------------------------------------------------------------------
  714.  */
  715. ReturnStatus
  716. Fscache_Write(cacheInfoPtr, flags, buffer, offset, lenPtr, remoteWaitPtr)
  717.     register Fscache_FileInfo *cacheInfoPtr;    /* Cache state for the file. */
  718.     int            flags;        /* FS_USER | FS_APPEND | 
  719.                      * FS_SERVER_WRITE_THRU */
  720.     register Address     buffer;        /* Buffer to write from */
  721.     int         offset;        /* Byte offset */
  722.     int         *lenPtr;    /* In/Out byte count */
  723.     Sync_RemoteWaiter     *remoteWaitPtr;    /* Process info for remote waiting */
  724. {
  725.     register int     size;        /* The current size left to write */
  726.     register int     toWrite;    /* Amount to write each iteration */
  727.     int            toAlloc;    /* Amount of disk space to allocate.*/
  728.     register int     blockNum;    /* The current block being written */
  729.     Fscache_Block     *blockPtr;    /* From fetching cached blocks */
  730.     int            blockSize;    /* The number of bytes in the current
  731.                      * block. */
  732.     ReturnStatus     status = SUCCESS; /* Return from I/O operations */
  733.     int            firstBlock;    /* The first block of the write */
  734.     int            lastBlock;    /* The last block to write */
  735.     Boolean        found;        /* From fetching cached blocks */
  736.     int            oldOffset;    /* Initial value of the offset */
  737.     int            lastFileBlock;    /* Last block in the file */
  738.     int            blockAddr;    /* For allocating blocks */
  739.     Boolean        newBlock;    /* A brand new block was allocated. */
  740.     time_t        modTime;    /* File modify time. */
  741.     Boolean        dontBlock;    /* TRUE if lower levels shouldn't block
  742.                      * because we can block up higher */
  743.  
  744.     /*
  745.      * Serialize access to the cache for this file.
  746.      */
  747.     LOCK_MONITOR;
  748.  
  749.     if (cacheInfoPtr->flags & FSCACHE_FILE_NOT_CACHEABLE) {
  750.     /*
  751.      * Not cached.  The flag is checked here under monitor lock.
  752.      */
  753.     status = FS_NOT_CACHEABLE;
  754.     goto exit;
  755.     }
  756.     if (cacheInfoPtr->flags & FSCACHE_FILE_GONE) {
  757.     /*
  758.      * A delayed write is arriving as the file is being deleted.
  759.      */
  760.     printf( "Write to deleted file #%d\n",
  761.             cacheInfoPtr->hdrPtr->fileID.minor);
  762.     status = FS_FILE_REMOVED;
  763.     *lenPtr = 0;
  764.     goto exit;
  765.     }
  766.     /*
  767.      * Determine where to start writing.
  768.      */
  769.     if (flags & FS_APPEND) {
  770.     offset = cacheInfoPtr->attr.lastByte + 1;
  771.     }
  772.     oldOffset = offset;
  773.     size = *lenPtr;
  774.     *lenPtr = 0;
  775.  
  776.     /*
  777.      * Determine the range of blocks to write and where the current last block
  778.      * in the file is.
  779.      */
  780.     firstBlock = (unsigned int) offset / FS_BLOCK_SIZE; 
  781.     lastBlock = (unsigned int) (offset + size - 1) / FS_BLOCK_SIZE;
  782.     if (cacheInfoPtr->attr.lastByte == -1) {
  783.     lastFileBlock = -1;
  784.     } else {
  785.     lastFileBlock = ((unsigned int) cacheInfoPtr->attr.lastByte) /
  786.                 FS_BLOCK_SIZE;
  787.     }
  788.     /*
  789.      * If we have a handle on a process then our caller can block it.
  790.      * Otherwise we have to block at a low level in FetchBlock.
  791.      */
  792.     if ((remoteWaitPtr != (Sync_RemoteWaiter *)NIL) &&
  793.     (remoteWaitPtr->pid != (Proc_PID)NIL)) {
  794.     dontBlock = FSCACHE_DONT_BLOCK;
  795.     } else {
  796.     dontBlock = 0;
  797.     }
  798.  
  799.     /*
  800.      * Put the data into the cache a block at a time.
  801.      */
  802.     for (blockNum = firstBlock; 
  803.      blockNum <= lastBlock; 
  804.      blockNum++, size -= toWrite, buffer += toWrite, offset += toWrite) {
  805.  
  806.     /*
  807.      * Determine the number of bytes to write into the cache block
  808.      * this go around and the number of bytes to allocate on disk.
  809.      */
  810.     if ((unsigned int) (offset + size - 1) / FS_BLOCK_SIZE > blockNum) {
  811.         /*
  812.          * Writing will go into the next block.  In this case fill up the 
  813.          * rest of the current block and allocate space for the rest of
  814.          * the current block.
  815.          */
  816.         toWrite = FS_BLOCK_SIZE - (offset & FS_BLOCK_OFFSET_MASK);
  817.         toAlloc = toWrite;
  818.     } else {
  819.         /*
  820.          * The write ends in this block.
  821.          * There are two cases for disk allocation:
  822.          *   1) We are writing before the last byte in the file.  In this
  823.          *      case allocate up to the last byte or the end of the
  824.          *      current block whichever comes first.
  825.          *   2) We are after the last byte in the file.  In this case just
  826.          *        allocate space for the newly written bytes.
  827.          */
  828.         toWrite = size;
  829.         if (offset + toWrite - 1 < cacheInfoPtr->attr.lastByte) {
  830.         if (cacheInfoPtr->attr.lastByte >=
  831.                 (blockNum + 1) * FS_BLOCK_SIZE) {
  832.             toAlloc = FS_BLOCK_SIZE - (offset & FS_BLOCK_OFFSET_MASK);
  833.         } else {
  834.             toAlloc = cacheInfoPtr->attr.lastByte - offset + 1;
  835.         }
  836.         } else {
  837.         toAlloc = toWrite;
  838.         }
  839.     }
  840.  
  841.     /*
  842.      * Allocate space behind the cache block.
  843.      */
  844.     status = (cacheInfoPtr->backendPtr->ioProcs.allocate)(cacheInfoPtr->hdrPtr,
  845.             offset, toAlloc, dontBlock, &blockAddr, &newBlock);
  846. #ifdef lint
  847.     status = Fsdm_BlockAllocate(cacheInfoPtr->hdrPtr,
  848.             offset, toAlloc, dontBlock, &blockAddr, &newBlock);
  849.     status = FsrmtFileBlockAllocate(cacheInfoPtr->hdrPtr,
  850.             offset, toAlloc, dontBlock, &blockAddr, &newBlock);
  851. #endif /* lint */
  852.  
  853.     if (blockAddr == FSDM_NIL_INDEX) {
  854.         if (status == SUCCESS) {
  855.         if ((cacheInfoPtr->flags & FSCACHE_ALLOC_FAILED) == 0) {
  856.             printf("%s: allocator returned SUCCESS but no block.\n",
  857.                "Fscache_Write"); /* DEBUG */
  858.         }
  859.         status = FS_NO_DISK_SPACE;
  860.         }
  861.         blockPtr = (Fscache_Block *)NIL;
  862.     } else {
  863.         fs_Stats.blockCache.writeAccesses++;
  864.         Fscache_FetchBlock(cacheInfoPtr, blockNum, 
  865.          (int)(FSCACHE_IO_IN_PROGRESS | FSCACHE_DATA_BLOCK | dontBlock),
  866.          &blockPtr, &found);
  867.         if (blockPtr == (Fscache_Block *)NIL) {
  868.         status = FS_WOULD_BLOCK;
  869.         }
  870.     }
  871.     if (blockPtr == (Fscache_Block *)NIL) {
  872.         if (status == FS_NO_DISK_SPACE) {
  873.         /*
  874.          * Limit the number of "Alloc failed" messages to 1 per file.
  875.          * Servers with hard-copy consoles like this feature.
  876.          */
  877.         if ((cacheInfoPtr->flags & FSCACHE_ALLOC_FAILED) == 0) {
  878.             cacheInfoPtr->flags |= FSCACHE_ALLOC_FAILED;
  879.             printf("Fscache_Write: Alloc failed <%d,%d> \"%s\" %s\n",
  880.             cacheInfoPtr->hdrPtr->fileID.major,
  881.             cacheInfoPtr->hdrPtr->fileID.major,
  882.             Fsutil_HandleName(cacheInfoPtr->hdrPtr),
  883.             "DISK FULL");
  884.         }
  885.         }
  886.         break;
  887.     } else {
  888.         cacheInfoPtr->flags &= ~FSCACHE_ALLOC_FAILED;
  889.     }
  890.  
  891.  
  892.     if (toWrite == FS_BLOCK_SIZE) {
  893.         if (found) {
  894.         fs_Stats.blockCache.overWrites++;
  895.         }
  896.     } else {
  897.         /*
  898.          * Check if are writing into the middle of the file and are not 
  899.          * overwriting the block.  If so have to read the block in if
  900.          * it is not in the cache.
  901.          */
  902.         if (blockNum <= lastFileBlock && !newBlock) {
  903.         if (found) {
  904.             fs_Stats.blockCache.partialWriteHits++;
  905.             if (blockPtr->flags & FSCACHE_READ_AHEAD_BLOCK) {
  906.             fs_Stats.blockCache.readAheadHits++;
  907.             }
  908.         } else {
  909.             fs_Stats.blockCache.partialWriteMisses++;
  910.             status = (cacheInfoPtr->backendPtr->ioProcs.blockRead)
  911.             (cacheInfoPtr->hdrPtr, blockPtr, remoteWaitPtr);
  912. #ifdef lint
  913.             status = Fsio_FileBlockRead(cacheInfoPtr->hdrPtr, 
  914.                 blockPtr, remoteWaitPtr);
  915.             status = FsrmtFileBlockRead(cacheInfoPtr->hdrPtr,
  916.                 blockPtr, remoteWaitPtr);
  917. #endif /* lint */
  918.             if (status != SUCCESS) {
  919.             fs_Stats.blockCache.domainReadFails++;
  920.             Fscache_UnlockBlock(blockPtr, (time_t)0, -1, 0,
  921.                 FSCACHE_DELETE_BLOCK);
  922.             break;
  923.             }
  924.         }
  925.         } else {
  926.         /*
  927.          * We are writing to the end of the file or the block
  928.          * that we are writing to is brand new.  In this case zero
  929.          * fill the block if it isn't in the cache yet.
  930.          */
  931.         if (!found) {
  932.             fs_Stats.blockCache.writeZeroFills2++;
  933.             bzero(blockPtr->blockAddr, FS_BLOCK_SIZE);
  934.         }
  935.         }
  936.     }
  937.  
  938.     /*
  939.      * Copy the bytes into the block.
  940.      */
  941.     if (flags & FS_USER) {
  942.         if (Vm_CopyIn(toWrite, buffer, blockPtr->blockAddr + 
  943.                 (offset & FS_BLOCK_OFFSET_MASK)) != SUCCESS) {
  944.         status = SYS_ARG_NOACCESS;
  945.         Fscache_UnlockBlock(blockPtr, (time_t)0, -1, 0,
  946.                     FSCACHE_DELETE_BLOCK);
  947.         break;
  948.         }
  949.     } else {
  950.         bcopy(buffer, blockPtr->blockAddr + (offset & FS_BLOCK_OFFSET_MASK), toWrite);
  951.     }
  952.  
  953.     /*
  954.      * If the block is write-thru then write the data through to the 
  955.      * server and then check the block back in as clean.
  956.      * THIS IS A GORY HACK that limits the use of FS_SERVER_WRITE_THRU
  957.      * to the client.
  958.      */
  959.     if (flags & FS_SERVER_WRITE_THRU) {
  960.         Fs_Stream    dummyStream;
  961.         Fs_IOParam    io;
  962.         Fs_IOReply    reply;
  963.  
  964.         io.buffer = blockPtr->blockAddr + (offset & FS_BLOCK_OFFSET_MASK);
  965.         io.length = toWrite;
  966.         io.offset = offset;
  967.         io.flags = flags | FS_CLIENT_CACHE_WRITE;
  968.         io.flags &= ~(FS_USER | FS_SERVER_WRITE_THRU);
  969.  
  970.         dummyStream.hdr.fileID.type = -1;
  971.         dummyStream.ioHandlePtr = cacheInfoPtr->hdrPtr;
  972.         status = Fsrmt_Write(&dummyStream, &io,
  973.              (Sync_RemoteWaiter *)NIL, &reply);
  974.         if (status != SUCCESS) {
  975.         Fscache_UnlockBlock(blockPtr, (time_t)0, -1, 0,
  976.                     FSCACHE_DELETE_BLOCK);
  977.         break;
  978.         }
  979.         modTime = 0;
  980.     } else {
  981.         modTime = Fsutil_TimeInSeconds();
  982.     }
  983.  
  984.     /*
  985.      * Return the block to the cache.  At this time the block
  986.      * size is changed (by UnlockBlock). 
  987.      */
  988.     if (offset + toWrite - 1 > cacheInfoPtr->attr.lastByte) {
  989.         cacheInfoPtr->attr.lastByte = offset + toWrite - 1;
  990.     }
  991.     blockSize = cacheInfoPtr->attr.lastByte + 1 -
  992.             (blockNum * FS_BLOCK_SIZE);
  993.     if (blockSize > FS_BLOCK_SIZE) {
  994.         blockSize = FS_BLOCK_SIZE;
  995.     }
  996.     Fscache_UnlockBlock(blockPtr, modTime, blockAddr,
  997.         blockSize, FSCACHE_CLEAR_READ_AHEAD |
  998.         ((flags&FS_WRITE_TO_DISK) ?
  999.             FSCACHE_WRITE_TO_DISK : 0));
  1000.     }
  1001.  
  1002.     *lenPtr = offset - oldOffset;
  1003.     Fs_StatAdd(offset - oldOffset, fs_Stats.blockCache.bytesWritten,
  1004.            fs_Stats.blockCache.bytesWrittenOverflow);
  1005.  
  1006.     /*
  1007.      * Update the firstByte so that Fs_Read knows there is data.
  1008.      * This is support for named pipes, which care about firstByte.
  1009.      */
  1010.     if (cacheInfoPtr->attr.firstByte == -1 && *lenPtr > 0) {
  1011.     cacheInfoPtr->attr.firstByte = 0;
  1012.     }
  1013.     if (!(flags & FS_CLIENT_CACHE_WRITE) && *lenPtr > 0) {
  1014.     /*
  1015.      * Update the modify time unless this write is a flush back from a
  1016.      * user cache in which case we already get the correct mod time
  1017.      * for the file when the client closes.
  1018.      */
  1019.     cacheInfoPtr->attr.modifyTime = Fsutil_TimeInSeconds();
  1020.     }
  1021. exit:
  1022.     if (status == FS_WOULD_BLOCK) {
  1023.     Fsutil_FastWaitListInsert(fscacheFullWaitList, remoteWaitPtr);
  1024.     }
  1025.     UNLOCK_MONITOR;
  1026.     return(status);
  1027. }
  1028.  
  1029. /*
  1030.  *----------------------------------------------------------------------
  1031.  *
  1032.  * Fscache_BlockRead --
  1033.  *
  1034.  *    Return a pointer to the cache block that contains a
  1035.  *    block of a file.  This is used to directly access cache blocks
  1036.  *    and so avoid the cost of a copy.  The number of valid bytes
  1037.  *    in the cache block is returned.
  1038.  *
  1039.  * Results:
  1040.  *    SUCCESS or error when reading file system block.  Upon failure,
  1041.  *    or a zero length read with the allocate flag not set, the cache block 
  1042.  *    is not locked down and the caller doesn't have to worry about it; 
  1043.  *    NIL is returned in *blockPtrPtr.
  1044.  *    This returns FS_WOULD_BLOCK if blockType includes FSCACHE_DONT_BLOCK
  1045.  *    and the cache is full.
  1046.  *
  1047.  * Side effects:
  1048.  *    The cache block is locked down, and its contents are filled in
  1049.  *    from disk if neccessary.  The caller has to unlock the block when done,
  1050.  *    if it is non-NIL.
  1051.  *
  1052.  *----------------------------------------------------------------------
  1053.  */
  1054.  
  1055. ReturnStatus
  1056. Fscache_BlockRead(cacheInfoPtr, blockNum, blockPtrPtr, numBytesPtr, blockType,
  1057.          allocate)
  1058.     register    Fscache_FileInfo *cacheInfoPtr;    /* File to read block from.
  1059.                          * Should be locked on entry */
  1060.     int                blockNum;    /* Block to read. */
  1061.     register    Fscache_Block    **blockPtrPtr;    /* Where to put pointer to 
  1062.                          * block.*/
  1063.     register    int        *numBytesPtr;    /* Return number of bytes 
  1064.                          * read. */
  1065.     int                blockType;    /* One of FSCACHE_DATA_BLOCK
  1066.                          * and FSCACHE_DIR_BLOCK.
  1067.                          * | FSCACHE_DONT_BLOCK */
  1068.     Boolean            allocate;    /* TRUE => return the cache
  1069.                          * block even though there
  1070.                          * is not data in it. */
  1071. {
  1072.     Boolean        found;
  1073.     ReturnStatus    status = SUCCESS;
  1074.     int            offset;
  1075.     Fscache_Block    *blockPtr;
  1076.  
  1077.     LOCK_MONITOR;
  1078.  
  1079.     *blockPtrPtr = (Fscache_Block *)NIL;
  1080.     *numBytesPtr = 0;
  1081.  
  1082.    if (cacheInfoPtr->flags & FSCACHE_FILE_NOT_CACHEABLE) {
  1083.     panic( "Fscache_BlockRead, file not cacheable!\n");
  1084.     status = FS_NOT_CACHEABLE;
  1085.     goto exit;
  1086.     }
  1087.     offset = blockNum * FS_BLOCK_SIZE;
  1088.     if (offset > cacheInfoPtr->attr.lastByte) {
  1089.     status = SUCCESS;
  1090.     goto exit;
  1091.     }
  1092.     fs_Stats.blockCache.readAccesses++;
  1093.     if (blockType & FSCACHE_DIR_BLOCK) {
  1094.         fs_Stats.blockCache.dirBlockAccesses++;
  1095.     }
  1096.     Fscache_FetchBlock(cacheInfoPtr, blockNum, blockType,
  1097.             blockPtrPtr, &found);
  1098.     if (*blockPtrPtr == (Fscache_Block *)NIL) {
  1099.     status = FS_WOULD_BLOCK;
  1100.     goto exit;
  1101.     }
  1102.     blockPtr = *blockPtrPtr;
  1103.  
  1104.     if (!found) {
  1105.     /*
  1106.      * Read in the cache block.  If the block isn't full (includes EOF)
  1107.      * then blockSize is set and the rest of the cache block has
  1108.      * been zero filled.
  1109.      */
  1110.     status = (cacheInfoPtr->backendPtr->ioProcs.blockRead)
  1111.             (cacheInfoPtr->hdrPtr, blockPtr, (Sync_RemoteWaiter *) NIL);
  1112. #ifdef lint
  1113.     status = Fsdm_FileBlockRead(cacheInfoPtr->hdrPtr,
  1114.         blockPtr, (Sync_RemoteWaiter *) NIL);
  1115.     status = FsrmtFileBlockRead(cacheInfoPtr->hdrPtr,
  1116.         blockPtr, (Sync_RemoteWaiter *) NIL);
  1117. #endif /* lint */
  1118.     if (status == SUCCESS && blockPtr->blockSize == 0 &&
  1119.         offset < cacheInfoPtr->attr.lastByte + 1) {
  1120.         /*
  1121.          * Due to delayed writes the disk descriptor has no space allocated
  1122.          * and the file block read routine thinks we've read past eof.
  1123.          * Actually were in a hole in the file and should return zeros.
  1124.          * The blockRead routine always zero fills for us.
  1125.          */
  1126.         printf("Fscache_BlockRead: Giving zeros to \"%s\" <%d,%d> block %d amount %d\n",
  1127.             Fsutil_HandleName(cacheInfoPtr->hdrPtr),
  1128.             cacheInfoPtr->hdrPtr->fileID.major,
  1129.             cacheInfoPtr->hdrPtr->fileID.minor,
  1130.             blockPtr->blockNum,
  1131.             cacheInfoPtr->attr.lastByte - offset);
  1132.         blockPtr->blockSize = cacheInfoPtr->attr.lastByte - offset;
  1133.         if (blockPtr->blockSize > FS_BLOCK_SIZE) {
  1134.         blockPtr->blockSize = FS_BLOCK_SIZE;
  1135.         }
  1136.     }
  1137.     if ((status != SUCCESS) ||
  1138.         (blockPtr->blockSize == 0 && !allocate)) {
  1139.         /*
  1140.          * We hit a disk error or are really past the end-of-file.
  1141.          */
  1142.         Fscache_UnlockBlock(blockPtr, (time_t)0, -1, 0,
  1143.                 FSCACHE_DELETE_BLOCK);
  1144.         *blockPtrPtr = (Fscache_Block *)NIL;
  1145.     }
  1146.     } else {
  1147.     if (blockType & FSCACHE_DIR_BLOCK) {
  1148.         fs_Stats.blockCache.dirBlockHits++;
  1149.     }
  1150.     if (blockPtr->flags & FSCACHE_READ_AHEAD_BLOCK) {
  1151.         fs_Stats.blockCache.readAheadHits++;
  1152.     }
  1153.     if (blockPtr->timeDirtied != 0) {
  1154.         fs_Stats.blockCache.readHitsOnDirtyBlock++;
  1155.     } else {
  1156.         fs_Stats.blockCache.readHitsOnCleanBlock++;
  1157.     }
  1158.     }
  1159.     if (status == SUCCESS) {
  1160.     *numBytesPtr = blockPtr->blockSize;
  1161.     }
  1162.  
  1163.     if (blockType & FSCACHE_DIR_BLOCK) {
  1164.     fs_Stats.blockCache.dirBytesRead += blockPtr->blockSize;
  1165.     } else {
  1166.     Fs_StatAdd(blockPtr->blockSize, fs_Stats.blockCache.bytesRead,
  1167.            fs_Stats.blockCache.bytesReadOverflow);
  1168.     }
  1169.     /*
  1170.      * Read ahead the next block.
  1171.      */
  1172.     FscacheReadAhead(cacheInfoPtr, blockNum + 1);
  1173. exit:
  1174.     UNLOCK_MONITOR;
  1175.     return(status);
  1176. }
  1177.  
  1178. /*
  1179.  *----------------------------------------------------------------------
  1180.  *
  1181.  * Fscache_Trunc --
  1182.  *
  1183.  *    Truncate data out of the cache.  This knows how to truncate
  1184.  *    Consuming streams.
  1185.  *
  1186.  * Results:
  1187.  *    The return status of backend truncate.
  1188.  *
  1189.  * Side effects:
  1190.  *    Data blocks are removed from the cache.  The file's first and
  1191.  *    last byte indexes get updated.  The modify time of the file
  1192.  *    gets set.
  1193.  *
  1194.  *----------------------------------------------------------------------
  1195.  */
  1196. ReturnStatus
  1197. Fscache_Trunc(cacheInfoPtr, length, flags)
  1198.     Fscache_FileInfo *cacheInfoPtr;
  1199.     int length;
  1200.     int flags;    /*  FSCACHE_TRUNC_DELETE */
  1201. {
  1202.     int firstBlock;
  1203.     int lastBlock;
  1204.     ReturnStatus status;
  1205.  
  1206.     LOCK_MONITOR;
  1207.  
  1208.     if (flags & FSCACHE_TRUNC_DELETE) {
  1209.     cacheInfoPtr->flags |= FSCACHE_FILE_GONE;
  1210.     }
  1211.     if ((cacheInfoPtr->flags & FS_NOT_CACHEABLE) == 0) {
  1212.     if (length - 1 < cacheInfoPtr->attr.lastByte) {
  1213.         /*
  1214.          * Do file like truncation, leave length bytes at the
  1215.          * beginning of the file.
  1216.          */
  1217.         if (length == 0) {
  1218.         firstBlock = 0;
  1219.         } else {
  1220.         firstBlock = (length - 1) / FS_BLOCK_SIZE + 1;
  1221.         }
  1222.         lastBlock = cacheInfoPtr->attr.lastByte / FS_BLOCK_SIZE;
  1223.             if (length - 1 < cacheInfoPtr->attr.firstByte) {
  1224.                 cacheInfoPtr->attr.lastByte = -1;
  1225.             cacheInfoPtr->attr.firstByte = -1;
  1226.             } else {
  1227.                 cacheInfoPtr->attr.lastByte = length - 1;
  1228.             }
  1229.         Fscache_FileInvalidate(cacheInfoPtr, firstBlock, lastBlock);
  1230.         if (firstBlock > 0) {
  1231.         Fscache_BlockTrunc(cacheInfoPtr, firstBlock - 1,
  1232.                   length - (firstBlock - 1) * FS_BLOCK_SIZE);
  1233.         }
  1234.         }
  1235.     cacheInfoPtr->attr.modifyTime = Fsutil_TimeInSeconds();
  1236.     }
  1237.     status = (cacheInfoPtr->backendPtr->ioProcs.truncate)(cacheInfoPtr->hdrPtr,
  1238.             length, (flags & FSCACHE_TRUNC_DELETE) != 0);
  1239.     UNLOCK_MONITOR;
  1240.     return status;
  1241. }
  1242.